%%--- coding:utf-8 ---
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% File Name: mc_pool
%%% Created on : 2024/9/5 22:24
%%% @author Gaylen 252323463@qq.com
%%% @copyright (C) 2024, freedom
%%% @doc
%%%     数据库解码编码进程
%%% @end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-module(mc_pool).
-behaviour(gen_server).
-author("Gaylen").
-include("mongodb_driver.hrl").

%% API
-export([start_link/0, close/1, sync_close/1]).
-export([
    init/1,
    handle_call/3,
    handle_cast/2,
    handle_info/2,
    terminate/2,
    code_change/3,
    async_apply/5,
    sync_apply/3
]).

start_link() ->
    gen_server:start_link(?MODULE, [], []).

close(Pid) ->
    gen_server:cast(Pid, halt).

sync_close(Pid) ->
    gen_server:call(Pid, halt, infinity).


init([]) ->
    State = mc_pool_logic:init(),
    {ok, State}.

handle_call({sync_apply, Func, Args}, _From, State) ->
    {ok, NewState, Result} = erlang:apply(Func, [State | Args]),
    {reply, Result, NewState};
handle_call(halt, _From, State) ->
    {stop, normal, ok, State};
handle_call(_Info, _From, State) ->
    {reply, ok, State}.

handle_cast({async_apply, Func, Args, FromPid, ReplyFunc, ReplyArgs}, State) ->
    {ok, NewState, Result} = erlang:apply(Func, [State | Args]),
    if
        ReplyFunc =/= undefined andalso ReplyArgs =/= undefined ->
            FromPid ! {async_apply_reply, ReplyFunc, [Result | ReplyArgs]};
        true ->
            skip
    end,
    {noreply, NewState};
handle_cast(halt, State) ->
    {stop, normal, State};
handle_cast(_Info, State) ->
    {noreply, State}.

handle_info({async_apply_reply, ReplyFunc, ReplyArgs}, State) ->
    erlang:apply(ReplyFunc, ReplyArgs),
    {noreply, State};
handle_info(_Info, State) ->
    {noreply, State}.

terminate(Reason, State) ->
    {stop, Reason, State}.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

async_apply(PoolPid, Func, Args, ReplyFunc, ReplyArgs) ->
    gen_server:cast(PoolPid, {async_apply, Func, Args, self(), ReplyFunc, ReplyArgs}).

sync_apply(PoolPid, Func, Args) ->
    gen_server:call(PoolPid, {sync_apply, Func, Args}).